/**
 * 1.创建对象有两种方式
 *  new Object();
 *  let person = {name:""}
 *  8.1.1 属性的类型 属性分2种:数据属性和访问器属性
 *      内部属性一般用两个括号表示[[]],开发者不能在js中直接访问这些特性。
 *      1、数据属性 4个特性
 *      数据属性包含一个保存数据值的位置。
 *        [[configurable]]:是否可以通过delete删除并重新定义，是否可以修改它的特性，以及是否可以把它改为访问器属性。注意是所有直接定义在对象上的属性的这个特性都是 true，手动赋值的是false
 *        [[Enumerable]]:表示属性的值是否可以通过for-in循环返回。注意是所有直接定义在对象上的属性的这个特性都是 true，手动赋值的是false。
 *        [[Writable]]:表示属性的值是否可以被修改。注意是所有直接定义在对象上的属性的这个特性都是 true，手动赋值的是false。
 *        [[Value]]:包含属性实际的值。读取和写入属性值的位置。这个特性默认值为undefined
 *      要修改这些对象的属性需要使用Object.defineProperty()方法。
 *      2.访问器属性 4个特性 访问属性不包含数据值 包含一个getter 和 一个setter函数(非必须)。
 *        [[Configurable]]:是否可以通过delete删除。注意是所有直接定义在对象上的属性的这个特性都是 true，手动赋值的是false。
 *        [[Enumerable]]:表示是否可以通过for-in循环。注意是所有直接定义在对象上的属性的这个特性都是 true，手动赋值的是false。
 *        [[Get]]：获取函数，在读取属性时调用。默认为undefined
 *        [[Set]]:设置函数，在写入属性时调用。默认值为undefined
 *        访问器属性是不能直接定义的，必须使用Object.defineProperty()。
 *   8.1.2 定义多个属性
 *      定义多个属性使用Object.defineProperties()
 *      这个方法可以通过多个描述符一次性定义多个属性。它接收两个参数：要为之添加或修改属性的对象和另一个描述符对象，其属性与要添加或修改的属性一一对应。
 *   8.1.3 读取属性的特性
 *      Object.getOwnPropertyDescriptor()方法可以取得指定属性的属性描述等。
 *      获取全部属性使用Object.getOwnPropertyDescriptors(book)
 *   8.1.4 合并对象
 *      1.es6的方法 Object.assign()  浅拷贝
 *      复制可枚举的和自有属性。已字符串和符号为键的属性会被复制。
 *      Object.assign()实际上对每个源对象执行的是浅复制。如果多个源对象都有相同的属性，则使用最后一个复制的值。此外，从源对象访问器属性取得的值，比如获取函数，会作为一个静态值赋给目
 *      标对象。换句话说，不能在两个对象间转移获取函数和设置函数。
 *      如果目标对象有多个相同的属性，那么取后者。
 *      如果赋值的过程报错，不会回滚。可能只会完成部分复制的方法。
 *   8.1.5 对象标识及相等判定
 *      Object.js() 这个方法与===很像，考虑到了很多边界情况
 *   8.1.6 增强的对象语法
 *      1.属性值简写
 *      2.可计算属性 属性名用[]括起来就是变量
 *   8.1.7 对象解构
 *      对象解构就是用与对象匹配的结构来实现对象属性赋值。
 *       let { name, age } = person;   这个就是解构赋值
 *      1.可以嵌套解构
 *      2.部分解构
 *      3.在参数列表中也可以解构。
 * 
 *  
 */
const persong = {
    name:"Nicholas"
}
console.log(persong.name, '原始值')
Object.defineProperty(persong, "name", {
    writable: false,
    value:"GLA"
})
console.log(persong.name, "设定值")
persong.name = "GAA"
console.log(persong.name, "修改值") // 无法修改，因为设置了writeable 为false
// 访问属性
const book = {
    year_: 2017,
    edition:1
}
Object.defineProperty(book, "month", {
    value:"12"
})
Object.defineProperty(book, "year", {
    get() { 
        return this.year_;
    },
    set(newValue) {
        if (newValue > 2017) {
            this.year_ = newValue;
            this.edition += newValue -2017
         }
    }
})
book.year = 2018
console.log(book.edition)
// book.year_ = 2011
console.log(book.year_)

// 8.1.2
const bookMore = {}
Object.defineProperties(bookMore, {
    year_: {
        value:2017
    },
    edition: {
        value:1
    },
    year: {
        get() { 
            return this.year_;
        },
        set(newValue) { 
            if (newValue>2017) { 
                this.year_ = newValue
                this.edition += newValue - 2017
            }
        }
    }
    
})
// 8.1.3 获得属性
// 获得一个属性
const descriptor = Object.getOwnPropertyDescriptor(book, "year_")
console.log(descriptor.value)
console.log(descriptor.configurable)
console.log(typeof descriptor.get)
const descriptorYear = Object.getOwnPropertyDescriptor(book, "year")
console.log(descriptorYear.value)
console.log(descriptorYear.configurable)
console.log(typeof descriptorYear.get)
const descriptorMonth = Object.getOwnPropertyDescriptor(book, "month")
console.log(descriptorMonth.value)
console.log(descriptorMonth.configurable)
console.log(typeof descriptorMonth.get)
// 获得多个属性 一个静态方法
console.log(Object.getOwnPropertyDescriptors(book))

// 8.1.4 复制对象
let dest, src, result;
dest = {}
src = {
    id:'src'
}
result = Object.assign(dest, src)
// 8.1.6 可计算属性
const nemaKey = 'name';
result[nemaKey] = 'tom'
console.log(result.name)
let person = {
    [nemaKey]:'jl'
}
console.log(person)